package com.callbell.cas.handler;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.jasig.cas.CentralAuthenticationService;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.jasig.cas.ticket.TicketException;
import org.jasig.cas.web.support.CookieRetrievingCookieGenerator;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.alibaba.fastjson.JSONObject;
import com.callbell.cas.exception.LoginValidateException;
import com.callbell.cas.util.HttpClientUtil;
import com.callbell.cas.util.ResourceBundleUtil;

/**
 * 登陆回调
 * @author xlh
 *
 */
@SuppressWarnings("deprecation")
public class ThirdLoginCallbackController extends AbstractController{
	
	private CentralAuthenticationService centralAuthenticationService;
	
	private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator;
	
	private final String charset = "utf-8";
	
	private SimpleJdbcTemplate jdbcTemplate;
	
	private DataSource dataSource;

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {

		String code = ServletRequestUtils.getStringParameter(request, "code");// 授权后返回的code
		String state = ServletRequestUtils.getStringParameter(request, "state");//扫码时生成的随机码
		String prefixUrl = ResourceBundleUtil.getProperty("wechat.granted.prefixUrl");//授权后接口调用地址前缀
		String appId = ResourceBundleUtil.getProperty("wechat.login.appid");
		String appSecret = ResourceBundleUtil.getProperty("wechat.login.appSecret");
		//String loginState = request.getSession().getAttribute("loginState").toString();
//		String loginState = "fgjh654fgjh654";
//		String service = "http://192.168.1.39/ocl-server/shiro-cas";
		String loginState = null;
		String service = null;
		if("fgjh654fgjh654".equals(state)){
			loginState = "fgjh654fgjh654";
			service = ResourceBundleUtil.getProperty("server.ocl.host");
		}

		
		ModelAndView signinView = new ModelAndView();
		HttpClientUtil httpClient = new HttpClientUtil();
		//获取access_token
		String result = getAccessToken(state, loginState, appId, appSecret, code, prefixUrl, httpClient);
		
		String viewName = null;
		if(result != null){//根据access_token获取个人信息
			JSONObject json = JSONObject.parseObject(result);
			String openId = json.getString("openid");
			String userInfo = getInfo(result, prefixUrl, httpClient);
			if(userInfo != null && !"".equals(userInfo)){//保存或返回用户信息
				List<Map<String, Object>> list = jdbcTemplate.queryForList("select user_id as userId from user where account=?", openId);
				String password = "0", loginType = "1", loginName = openId;
				if(list != null && list.size() > 0){
					viewName = forwardLoginSuccess(request, response, loginName, password, loginType,service);
				} else {//第一次登录保存第三方返回的某些必要信息
					saveUserInfo(userInfo, openId);
					viewName = forwardLoginSuccess(request, response, loginName, password, loginType,service);
				}
			}
			signinView.setViewName(viewName);
		}
		request.getSession().removeAttribute("loginState");
		return signinView;
	}
	
	private String forwardLoginSuccess(HttpServletRequest request, HttpServletResponse response, String loginName, String password, String loginType,String service) throws IOException{
		UsernamePasswordCredentials credentials = new UsernamePasswordCredentials();
		credentials.setUsername(loginName);
		credentials.setPassword(password);
		credentials.setLoginType(loginType);
		
		try {
			String ticketGrantingTicket = centralAuthenticationService.createTicketGrantingTicket(credentials);
			ticketGrantingTicketCookieGenerator.addCookie(request, response, ticketGrantingTicket);
		} catch (TicketException e) {
			e.printStackTrace();
		}
		
//		String service = request.getSession().getAttribute("service").toString();//登录成功需要跳转的客户端地址
//		request.getSession().removeAttribute("service");
		//String service = "http://192.168.1.39/ocl-server/shiro-cas";
		return ("redirect:login" + (service.length() > 0 ? "?service=" + service : ""));
	}
	
	private String getAccessToken(String oldState, String localState, String appId, String appSecret, String code, String prefixUrl, HttpClientUtil httpClient) throws Exception{
		String grantType = "authorization_code";
		String result = null;
		if(oldState.equals(localState)){//当扫码时生成的state与授权通过后返回的state一致时才允许登陆
			String params = "appid="+ appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=" + grantType;
			String url = prefixUrl + "/oauth2/access_token";
			result = httpClient.doGet(url, params, charset);
		} else {
			throw new LoginValidateException(LoginValidateException.ERROR_STATE);
		}
		return result;
	}
	
	private String getInfo(String result, String prefixUrl, HttpClientUtil httpClient){
		JSONObject json = JSONObject.parseObject(result);
		String accessToken = json.getString("access_token");
		String openId = json.getString("openid");
		
		String getInfoUrl = prefixUrl + "/userinfo";
		String getInfoParam = "access_token=" + accessToken + "&openid=" + openId;
		String resultInfo = httpClient.doGet(getInfoUrl, getInfoParam, charset);
		return resultInfo;
	}
	
	private boolean saveUserInfo(String userInfo, String openId){
		JSONObject infoJson = JSONObject.parseObject(userInfo);
		Integer sex = infoJson.getInteger("sex");
		String nickName = infoJson.getString("nickname");
		
		Map<String, Object> valueMap = new HashMap<String, Object>();
		valueMap.put("oepn_id", openId);
		valueMap.put("nick_name", nickName);
		valueMap.put("sex", sex);
		valueMap.put("user_type", 1);
		valueMap.put("create_time", new Date());
		int count = jdbcTemplate.update("insert into user(account, nick_name, sex, user_type, create_time) "
				+ "values(:oepn_id, :nick_name, :sex, :user_type, :create_time)", valueMap);
		return count > 0 ? true : false;
	}
	
	public void setDataSource(final DataSource dataSource) {
		this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

	protected final DataSource getDataSource() {
		return this.dataSource;
	}
	
	public CentralAuthenticationService getCentralAuthenticationService() {
		return centralAuthenticationService;
	}

	public void setCentralAuthenticationService(CentralAuthenticationService centralAuthenticationService) {
		this.centralAuthenticationService = centralAuthenticationService;
	}

	public CookieRetrievingCookieGenerator getTicketGrantingTicketCookieGenerator() {
		return ticketGrantingTicketCookieGenerator;
	}

	public void setTicketGrantingTicketCookieGenerator(
			CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator) {
		this.ticketGrantingTicketCookieGenerator = ticketGrantingTicketCookieGenerator;
	}
}
